package com.cskaoyan.javase.oop3._0abstract._1basic;

/**
 * 抽象类的定义:
 *      在继承体系中，从祖先类开始，随着一个个子类的定义，子类变得越来越具体，而祖先类则更具有一般性和抽象性。在这种情况下，为了体现祖先类在设计上的抽象性，我们只将该类作为派生其他类的父类，而不能创建对象实例。这个时候，这样的类，我们称之为抽象类。
 *      1.抽象类是抽象的,它不能创建对象.
 *      2.(最重要)抽象类是在继承层次中,作为祖先类而存在的.
 *          也就是说,只有祖先类,才考虑设计为抽象类
 * 一般来说,在工作中,是很罕见定义抽象类的,但是会经常使用抽象类.
 *
 * 自此，我们已经引入了抽象类的概念。
 * 接下来，我们重点来研究一个抽象类的特点和使用。
 *
 * 抽象类的特点我们主要从以下角度：
 * 对于抽象类语法:
 * [修饰符列表] abstracts class 类名{
 *     //类体
 * }
 *
 * 1.抽象类的类名命名特点
 *      为了体现抽象类的特殊性,所以在命名上
 *      建议抽象类的类名以"Abstract"或者"Base"开头
 *
 * 2.能用哪些修饰符？
 *      和普通类一样,可以用访问权限修饰符
 *      要么public,要么缺省
 *
 *      抽象类是鼓励继承的,所以它和final关键字是冲突的
 *      final不能用来修饰抽象类
 *
 * 3.成员特点
 *      a.普通成员
 *      b.静态成员
 *      实测下来,抽象类和普通类一样,以上结构都可以定义
 *
 *      抽象类中的实现方法的意义:
 *          1.可以作为抽象父类的所有子类方法
 *              的一个默认实现
 *
 *          2.如果子类觉得这个默认实现可以用,那就直接用,反之子类可以重写该实现
 *          总之,选择的权力在子类手里.
 *
 *      c.抽象方法
 *          抽象类中是允许没有抽象方法的
 *          但是如果一个抽象类没有抽象方法,它的意义是什么?为什么要定义它呢?
 *          有些人会考虑禁止创建对象而把一个类设置为抽象,这显然是不合适的,违背了抽象类的使用原则
 *          实际开发中,禁止创建对象,只需要私有化构造器即可,抽象类是作为祖先类而存在的,不要做其它用途.
 *          抽象类就应该有抽象方法,没有抽象方法的抽象类毫无意义.
 *          抽象方法的语法:
 *   [修饰符列表] abstracts 返回值类型 方法名(形参列表);
 *   注: 抽象方法是鼓励继承和重写,所以一般来说,它的访问权限修饰符是public
 *
 *   抽象方法写在抽象父类中,起到"占位符"的作用,虽然它本身没有任何意义,但是普通子类一旦继承抽象类,就必须强制实现该抽象父类中的抽象方法.
 *
 *   如果抽象类的子类仍然是一个抽象类的话,那么就不强制实现抽象方法了,而是可以选择实现或者都不实现.
 *
 *   抽象方法中的abstract关键字,它和哪些修饰符是不能同时使用的?它不能用来修饰哪些方法?
 *   抽象方法的目的就是被重写,所以只要是不能被重写的方法,一律不能用abstract修饰,比如:
 *   1.私有方法,private
 *   2.静态方法,static
 *   3.构造方法
 *   4.final修饰的方法
 *
 *   抽象类有没有构造器呢?
 *      抽象类虽然自身不能创建对象,但是构造器的作用本身就是为了赋值,虽然它没有自身的对象,给自身成员变量赋值,但是可以给子类用,作用仍然是赋值,在创建子类对象的过程中,给父类自身成员变量赋值
 *
 *      在Java中所有类都有构造器,包括普通类,抽象类.
 *
 * 代码块:
 *      有构造器就有构造代码块
 *      也有静态代码块
 *
 * 综上所述,抽象类可以定义普通类能够定义的所有结构
 * 并且还多了一个抽象方法
 *
 * 思考:
 *      在不考虑创建对象的情况下,直接将一个类声明为abstract,有问题吗?会报错吗?
 *      不会,因为普通类中有的,抽象类都有
 *
 *
 * 抽象类的使用，我们主要探讨，它的子类特点。
 * 抽象类的子类可以有两种情况：
 *      1.普通类，普通类继承抽象类，必须实现所有的抽象方法。
 *      2.抽象类，抽象子类不需要实现抽象方法，抽象子类可以自由选择实现（或实现或不实现）。
 *
 * 扩展: 抽象类还可以继承一个普通类，实际上如果一个抽象类,它没有直接父类,那它就直接继承Object
 *
 * @since 16:28
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        System.out.println(AbstractPerson.grade);
        AbstractPerson.testStatic();

        Student s = new Student();
        System.out.println(s.age);
        s.test();

        System.out.println("--------------");
        Student s2 = new Student(18, "张三");
        System.out.println(s2.age);
        System.out.println(s2.getName());
    }
}

// 抽象的人类
abstract class AbstractPerson {
    int age;
    private String name;
    static String grade;

    {

    }

    static {
    }

    public AbstractPerson(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public AbstractPerson() {
    }

    public String getName() {
        return name;
    }

    public void test() {
    }

    public static void testStatic() {
    }

    // 定义抽象方法
    public abstract void testAbstract();

    public abstract void testAbstract2();
    // Illegal combination of modifiers: 'abstracts' and 'private'
    // private abstracts void testAbstract3();

    // Illegal combination of modifiers: 'abstracts' and 'static'
    // public static abstracts void testAbstract4();

    // Illegal combination of modifiers: 'abstracts' and 'final'
    // public final abstracts void testAbstract5();
}

// Class 'Student' must either be declared abstracts or implement abstracts method 'testAbstract()' in 'AbstractPerson'
/*
    重写父类抽象方法的办法:
        1.alt + 回车报错的位置,然后选择重写方法(建议)
        2.在子类中写抽象方法的名字(不建议)
        3.alt + insert
 */
class Student extends AbstractPerson {
    @Override
    public void test() {
        System.out.println("我不满意父类实现,重写它~~");
    }

    @Override
    public void testAbstract() {
        System.out.println("你真的是一个好人,但是我们不合适~~");
    }

    @Override
    public void testAbstract2() {
        System.out.println("现在你是我女朋友吗?那你说呢?");
    }

    public Student() {
        // super();
    }

    public Student(int age, String name) {
        super(age, name);
    }
}

abstract class BaseTeacher extends AbstractPerson {
    @Override
    public void testAbstract() {
    }

}


// Illegal combination of modifiers: 'final' and 'abstracts'
// final abstracts class AbstractPerson { }


